﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Antioch.Base.PlayerStates
{
    internal class Fall : IState
    {
        public void Enter(StateMachine Machine)
        {
            Machine.DrawComponent.Play("Fall", true);
            Machine.PhysicsComponent.PhysicsBody.GetFixtureList().SetFriction(0.0f);
        }

        public void Leave(StateMachine Machine)
        {
        }

        public void Update(StateMachine Machine)
        {
            if (Machine.PhysicsComponent.IsOnGround)
            {
                Machine.Transition(typeof(Land));
                Machine.Memory.LedgeHangPoint = null;
            }
            else
            {
                if (Machine.Input.RawAimStick.X > 0)
                    Machine.PlayerEntity.Facing = Jemgine.Data.Facings.Right;
                else if (Machine.Input.RawAimStick.X < 0)
                    Machine.PlayerEntity.Facing = Jemgine.Data.Facings.Left;

                Vector2 StickDir = new Vector2(Machine.Input.NavigationStick.X, 0);
                StickDir = Vector2.Transform(StickDir, Matrix.CreateRotationZ(Machine.PlayerEntity.Angle));

                Machine.PhysicsComponent.PhysicsBody.ApplyLinearImpulse(StickDir * Machine.Settings.HorizontalAirControl,
                    Machine.PhysicsComponent.PhysicsBody.Position);


                Vector2 GrabSpot = new Vector2(0, Machine.PhysicsComponent.Dimensions.Y / 2);
                switch (Machine.PlayerEntity.Facing)
                {
                    case Jemgine.Data.Facings.Left:
                        GrabSpot.X = -(Machine.PhysicsComponent.Dimensions.X / 2);
                        break;
                    case Jemgine.Data.Facings.Right:
                        GrabSpot.X = Machine.PhysicsComponent.Dimensions.X / 2;
                        break;
                }

                GrabSpot = Machine.PlayerEntity.TransformToWorldSpace(GrabSpot);

                Jemgine.Math.OBB GrabBox = new Jemgine.Math.OBB();
                GrabBox.Center = GrabSpot;
                GrabBox.Extents = Vector2.One;
                GrabBox.Angle = Machine.PhysicsComponent.PhysicsBody.GetAngle();

                float Angle = Jemgine.Math.Angle.Normalize(Machine.PhysicsComponent.PhysicsBody.GetAngle());

                List<PlayerNavigationNode> HitNodes = new List<PlayerNavigationNode>();
                
                if (Machine.NavigationModule != null &&
                    Machine.NavigationModule.FindCollidingNodes(GrabBox, (A) => HitNodes.Add(A) ) > 0)
                {
                    LedgeHangPoint HangPoint = null;
                    foreach (var Node in HitNodes) if (Node is LedgeHangPoint) HangPoint = Node as LedgeHangPoint;
                    if (HangPoint == null) return;
                    if (HangPoint == Machine.Memory.LedgeHangPoint) return;
                    if (!HangPoint.CanHang(Machine.PlayerEntity)) return;

                    Vector2 HangVector =
                        Vector2.Transform(HangPoint.Me.TransformToWorldSpace(HangPoint.Position)
                        - Machine.PhysicsComponent.PhysicsBody.Position, Matrix.CreateRotationZ(-Angle));

                    bool CanHang = true;

                    Vector2 LocalAnchorA = Vector2.Zero;

                    switch (Machine.PlayerEntity.Facing)
                    {
                        case Jemgine.Data.Facings.Left:
                            if (HangVector.X > 0) CanHang = false;
                            LocalAnchorA = new Vector2(-1.1f, 4);
                            break;
                        case Jemgine.Data.Facings.Right:
                            if (HangVector.X < 0) CanHang = false;
                            LocalAnchorA = new Vector2(1.1f, 4);
                            break;
                    }

                    if (!CanHang) return;

                    Box2D.XNA.RevoluteJointDef JointDef = new Box2D.XNA.RevoluteJointDef();
                    JointDef.bodyA = Machine.PhysicsComponent.PhysicsBody;
                    JointDef.bodyB = HangPoint.GetPhysicsBody();
                    JointDef.collideConnected = true;
                    JointDef.localAnchorB = HangPoint.Position;
                    JointDef.localAnchorA = LocalAnchorA;

                    Machine.Memory.LedgeHangPoint = HangPoint;
                    Machine.Memory.LedgeHangJoint = Machine.PhysicsModule.PhysicsSimulator.CreateJoint(JointDef);
                    Machine.Transition(typeof(HangFromLedge));
                }
            }
            
        }
    }
}
